# -*- coding: utf-8 -*-
"""
Chapter 2: Request and Response Handling

This demo covers:
- Accessing request data (URL parameters, form data, cookies, headers)
- Working with different HTTP methods
- Creating responses with various data types
- Setting cookies and headers
- Redirection and URL generation
- Error handling and aborting requests
"""

import os
import random

from flask import Flask, request, make_response, redirect, url_for, abort, jsonify
from markupsafe import escape

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'dev-secret-key')


# Home page with links to all examples
@app.route('/')
def index():
    """Display links to all request/response examples."""
    links = [
        ('Query Parameters', '/params'),
        ('Form Data', '/form'),
        ('Cookies', '/cookies'),
        ('Headers', '/headers'),
        ('Different HTTP Methods', '/methods'),
        ('JSON Responses', '/api/data'),
        ('Redirection', '/redirect-example'),
        ('Error Handling', '/error'),
        ('Manual Response', '/manual-response'),
    ]

    html = '''
    <!DOCTYPE html>
    <html>
    <head>
        <title>Chapter 2: Request and Response</title>
        <style>
            body { font-family: Arial, sans-serif; margin: 40px; }
            ul { list-style-type: none; padding: 0; }
            li { margin: 10px 0; }
            a { text-decoration: none; color: #007bff; padding: 8px 16px; border: 1px solid #007bff; border-radius: 4px; }
            a:hover { background-color: #007bff; color: white; }
        </style>
    </head>
    <body>
        <h1>Chapter 2: Request and Response Handling</h1>
        <ul>
    '''

    for text, url in links:
        html += f'<li><a href="{url}">{text}</a></li>'

    html += '''
        </ul>
    </body>
    </html>
    '''

    return html


# Query parameters example
@app.route('/params')
def params_example():
    """Demonstrate accessing query parameters.

    eg: /params?name=Alice&color=red&color=blue
    """
    # Get a single parameter with a default value
    name = request.args.get('name', 'Anonymous')

    # Get a parameter as a list (allows multiple values)
    colors = request.args.getlist('color')

    # Get all parameters as a dictionary-like object
    all_params = request.args.to_dict()

    html = f'''
    <!DOCTYPE html>
    <html>
    <head><title>Query Parameters</title></head>
    <body>
        <h1>Query Parameters Example</h1>
        <p>Name: {escape(name)}</p>
        <p>Colors: {', '.join(escape(c) for c in colors) if colors else 'None'}</p>
        <p>All Parameters: {escape(str(all_params))}</p>
        <p>Try: <a href="/params?name=Alice&color=red&color=blue">/params?name=Alice&color=red&color=blue</a></p>
        <p><a href="/">Back to Home</a></p>
    </body>
    </html>
    '''

    return html


# Form handling example
@app.route('/form', methods=['GET', 'POST'])
def form_example():
    """Demonstrate form handling."""
    if request.method == 'POST':
        # Access form data
        username = request.form.get('username', '')
        email = request.form.get('email', '')
        interests = request.form.getlist('interest')

        html = f'''
        <!DOCTYPE html>
        <html>
        <head><title>Form Submitted</title></head>
        <body>
            <h1>Form Data Received</h1>
            <p>Username: {escape(username)}</p>
            <p>Email: {escape(email)}</p>
            <p>Interests: {', '.join(escape(i) for i in interests)}</p>
            <p><a href="/form">Submit another form</a> | <a href="/">Back to Home</a></p>
        </body>
        </html>
        '''
        return html

    # GET request - display the form
    html = '''
    <!DOCTYPE html>
    <html>
    <head><title>Form Example</title></head>
    <body>
        <h1>User Registration Form</h1>
        <form method="POST">
            <p>
                <label for="username">Username:</label>
                <input type="text" id="username" name="username" required>
            </p>
            <p>
                <label for="email">Email:</label>
                <input type="email" id="email" name="email" required>
            </p>
            <p>
                <label>Interests:</label><br>
                <input type="checkbox" id="tech" name="interest" value="Technology">
                <label for="tech">Technology</label><br>
                
                <input type="checkbox" id="sports" name="interest" value="Sports">
                <label for="sports">Sports</label><br>
                
                <input type="checkbox" id="music" name="interest" value="Music">
                <label for="music">Music</label>
            </p>
            <p>
                <input type="submit" value="Register">
            </p>
        </form>
        <p><a href="/">Back to Home</a></p>
    </body>
    </html>
    '''
    return html


# Cookies example
@app.route('/cookies')
def cookies_example():
    """Demonstrate setting and reading cookies."""
    # Read cookies
    username = request.cookies.get('username', 'Guest')
    theme = request.cookies.get('theme', 'light')

    html = f'''
    <!DOCTYPE html>
    <html>
    <head><title>Cookies Example</title></head>
    <body>
        <h1>Cookies Example</h1>
        <p>Current cookies:</p>
        <ul>
            <li>Username: {escape(username)}</li>
            <li>Theme: {escape(theme)}</li>
        </ul>
        <p><a href="/set-cookies">Set Sample Cookies</a> | <a href="/">Back to Home</a></p>
    </body>
    </html>
    '''
    return html


@app.route('/set-cookies')
def set_cookies():
    """Set sample cookies and redirect to cookies example."""
    response = make_response(redirect(url_for('cookies_example')))
    response.set_cookie('username', 'FlaskDev', max_age=60 * 60 * 24 * 30)  # 30 days
    response.set_cookie('theme', 'dark')
    return response


# Headers example
@app.route('/headers')
def headers_example():
    """Demonstrate accessing request headers."""
    # Get specific headers
    user_agent = request.headers.get('User-Agent', 'Unknown')
    accept_language = request.headers.get('Accept-Language', 'Not specified')

    # Get all headers
    all_headers = dict(request.headers)

    html = f'''
    <!DOCTYPE html>
    <html>
    <head><title>Headers Example</title></head>
    <body>
        <h1>Request Headers</h1>
        <p>User Agent: {escape(user_agent)}</p>
        <p>Accept Language: {escape(accept_language)}</p>
        <details>
            <summary>All Headers</summary>
            <pre>{escape(str(all_headers))}</pre>
        </details>
        <p><a href="/">Back to Home</a></p>
    </body>
    </html>
    '''
    return html


# Different HTTP methods example
@app.route('/methods', methods=['GET', 'POST', 'PUT', 'DELETE'])
def methods_example():
    """Handle different HTTP methods."""
    method = request.method

    if method == 'GET':
        html = '''
        <!DOCTYPE html>
        <html>
        <head><title>HTTP Methods</title></head>
        <body>
            <h1>HTTP Methods Example</h1>
            <p>Current method: GET</p>
            
            <form method="POST">
                <p><input type="submit" value="Send POST Request"></p>
            </form>
            
            <form method="POST">
                <input type="hidden" name="_method" value="PUT">
                <p><input type="submit" value="Send PUT Request (simulated)"></p>
            </form>
            
            <form method="POST">
                <input type="hidden" name="_method" value="DELETE">
                <p><input type="submit" value="Send DELETE Request (simulated)"></p>
            </form>
            
            <p><a href="/">Back to Home</a></p>
        </body>
        </html>
        '''
        return html

    elif method == 'POST':
        # Check for method override
        override_method = request.form.get('_method', 'POST')
        if override_method in ['PUT', 'DELETE']:
            method = override_method

        html = f'''
        <!DOCTYPE html>
        <html>
        <head><title>Method Result</title></head>
        <body>
            <h1>Received {escape(method)} Request</h1>
            <p><a href="/methods">Try another method</a> | <a href="/">Back to Home</a></p>
        </body>
        </html>
        '''
        return html

    else:
        # For PUT and DELETE, return plain text
        return f'{method} request received', 200


# JSON API example
@app.route('/api/data')
def api_data():
    """Return JSON data."""
    data = {
        'message': 'Hello, API!',
        'status': 'success',
        'data': {
            'users': [
                {'id': 1, 'name': 'Alice'},
                {'id': 2, 'name': 'Bob'}
            ],
            'timestamp': '2023-01-01T12:00:00Z'
        }
    }
    return jsonify(data)


# Redirection example
@app.route('/redirect-example')
def redirect_example():
    """Demonstrate redirection."""
    # Redirect to a named route
    return redirect(url_for('params_example', name='RedirectedUser'))


# Error handling example
@app.route('/error')
def error_example():
    """Demonstrate error handling."""
    random_type = ['404', '500', '403']
    error_type = request.args.get('type', random.choice(random_type))

    if error_type == '404':
        abort(404)
    elif error_type == '500':
        abort(500)
    elif error_type == '403':
        abort(403)
    else:
        return '<h1>No error triggered</h1><p><a href="/">Back to Home</a></p>'


# Manual response creation
@app.route('/manual-response')
def manual_response():
    """Demonstrate manual response creation."""
    # Create a response manually
    response = make_response('<h1>Manual Response</h1><p>This response was created manually.</p>')
    response.status_code = 201  # Created
    response.headers['X-Custom-Header'] = 'Flask-Demo'
    return response


# Error handlers
@app.errorhandler(404)
def not_found(error):
    """Handle 404 errors."""
    return '<h1>Page Not Found</h1><p>404: The requested page could not be found.</p><p><a href="/">Go Home</a></p>', 404


@app.errorhandler(500)
def internal_error(error):
    """Handle 500 errors."""
    return '<h1>Internal Server Error</h1><p>500: An unexpected error occurred.</p><p><a href="/">Go Home</a></p>', 500


@app.errorhandler(403)
def forbidden(error):
    """Handle 403 errors."""
    return '<h1>Access Forbidden</h1><p>403: You do not have permission to access this resource.</p><p><a href="/">Go Home</a></p>', 403


if __name__ == '__main__':
    app.run(
        host=os.getenv('FLASK_HOST', '127.0.0.1'),
        port=int(os.getenv('FLASK_PORT', 5000)),
        debug=os.getenv('FLASK_DEBUG', 'True').lower() == 'true'
    )
